package com.his.api.aop;

import com.his.util.annotation.RequiresLogin;
import com.his.util.annotation.RequiresPermissions;
import com.his.util.constant.RedisConstant;
import com.his.util.mapper.RoleInterfaceMapper;
import com.his.util.result.RestResult;
import com.his.util.result.RestResultBuilder;
import com.his.util.result.ResultCode;
import com.his.util.util.StringUtil;
import org.aspectj.lang.ProceedingJoinPoint;
import org.aspectj.lang.annotation.Around;
import org.aspectj.lang.annotation.Aspect;
import org.aspectj.lang.annotation.Pointcut;
import org.aspectj.lang.reflect.MethodSignature;
import org.springframework.data.redis.core.RedisTemplate;
import org.springframework.stereotype.Component;
import org.springframework.web.context.request.RequestAttributes;
import org.springframework.web.context.request.RequestContextHolder;
import org.springframework.web.context.request.ServletRequestAttributes;

import javax.annotation.Resource;
import javax.servlet.http.HttpServletRequest;
import java.lang.reflect.Method;

@Aspect
@Component
public class PreAuthorizeAspect {
    @Resource
    private RedisTemplate redisTemplate;

    @Resource
    private RoleInterfaceMapper roleInterfaceMapper;

    @Pointcut("@annotation(com.his.util.annotation.RequiresLogin) || @annotation(com.his.util.annotation.RequiresPermissions)")
    public void pointcut() {
    }

    @Around("pointcut()")
    public Object around(ProceedingJoinPoint joinPoint) throws Throwable {
        MethodSignature signature = (MethodSignature) joinPoint.getSignature();
        Method method = signature.getMethod();

        RestResult restResult = null;

//        restResult = checkPermissions(restResult, method);
        restResult = checkLogin(restResult, method);

        if (restResult != null) {
            return restResult;
        }
        return joinPoint.proceed();
    }

    private RestResult checkLogin(RestResult restResult, Method method) {
        if (!method.isAnnotationPresent(RequiresLogin.class)) {
            return null;
        }

        String authorization = getHeader("authorization");

        if (authorization == null) {
            return new RestResultBuilder().fail(ResultCode.TOKEN_MISSION);
        }

        String userId = (String) redisTemplate.opsForValue().get(RedisConstant.getPatientAndAuthorization(authorization));

        if (userId == null) {
            return new RestResultBuilder().fail(ResultCode.TOKEN_OVERDUE);
        }

        return null;
    }

    private RestResult checkPermissions(RestResult restResult, Method method) {
        if (!method.isAnnotationPresent(RequiresPermissions.class)) {
            return null;
        }

        String authorization = getHeader("authorization");

        Integer roleId = StringUtil.getId(RedisConstant.ROLE,
                (String) redisTemplate.opsForValue().get(RedisConstant.getRoleAndAuthorization(authorization)));

        Integer isPermission = roleInterfaceMapper.selectInterfaceIdByRoleIdAndUrl(
                roleId,
                getUrl()
        );

        if (isPermission == null) {
            return new RestResultBuilder().fail(ResultCode.HAVE_NO_LEGAL_POWER);
        }

        return null;
    }

    private String getHeader(String name) {
        RequestAttributes requestAttributes = RequestContextHolder.getRequestAttributes();
        ServletRequestAttributes servletRequestAttributes = (ServletRequestAttributes) requestAttributes;
        HttpServletRequest request = servletRequestAttributes.getRequest();

        return request.getHeader(name);
    }

    private String getUrl() {
        RequestAttributes requestAttributes = RequestContextHolder.getRequestAttributes();
        ServletRequestAttributes servletRequestAttributes = (ServletRequestAttributes) requestAttributes;
        HttpServletRequest request = servletRequestAttributes.getRequest();

        return request.getServletPath();
    }
}
